package tr.helper.service;

import static cn.hutool.core.util.CharsetUtil.CHARSET_UTF_8;

import cn.hutool.core.net.URLEncoder;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import java.io.IOException;
import java.math.BigDecimal;
import java.net.HttpCookie;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.lang3.StringUtils;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import tr.helper.CommonUtil;
import tr.helper.SpiderUtil;
import tr.helper.domain.LoginRequest;
import tr.helper.domain.TransferUResponse;

/**
 * tr-service
 * 外汇数据获取统一通过该服务
 *
 * @author MrYe
 * @date 2022-01-13 15:31
 */
public class TrService {

    private static final String CSRF_PATH = "/chs/login";
    private static final String CAPTCHA_CODE_PATH = "/captcha/flat2?eYOfimPn=";
    /**
     * 交易信息
     */
    private static final String FUNDS_PATH = "/chs/member/fundaccountlist";
    private static final String CHS_PATH = "/chs";
    private static final String CONVERT_U_PATH = "/chs/make-convertwtou";
    private static final String TRANSFER_U_PATH = "/chs/make-transferu";
    private static final String CANCEL_PATH = "/chs/make-unsubscribefund";
    /**
     * 验证码
     */
    private static final String VERIFY_PATH = "/chs/account/getVerification";
    private static final String PASSWORD_PATH = "/chs/account/updatePassword";
    private static final String TRANSFER_U_LIST_PATH = "/chs/member/ulist?start=0&length=2000";
    /**
     * 交易列表
     */
    private static final String LIST_PATH = "/chs/member/fundtradeaccountlist";
    /**
     * 交易明细
     */
    private static final String DETAIL_PATH = "/chs/misc/show-modal4?id=";
    /**
     * 汇率
     */
    private static final String RATE_PATH = "http://api.k780.com/?app=finance.rate&scur=USD&tcur=CNY&appkey=10003&sign=b59bc3ef6191eb9f747dd4e83c99f2a4";
    /**
     * 验证器绑定地址
     */
    private static final String VALIDATOR_BIND_PATH = "/chs/settings/postAuth";
    /**
     * 校验码地址重新绑定
     */
    private static final String VALIDATOR_CLEAR_BIND_PATH = "/chs/settings/postResetAuth";
    private static final String SEC_PATH = "/chs/settings/authenticatorConnect";
    private String host;

    public TrService() {
        this.host = "https://pixelgatetech.com";
    }

    public TrService(String host) {
        this.host = host;
    }

    public String getSec(String cookies) {
        Map<String, String> cookieMap = CommonUtil.cookieToMap(cookies);
        Document doc;
        try {
            doc = Jsoup.connect(host + SEC_PATH).ignoreHttpErrors(true)
                .ignoreContentType(true)
                .cookies(cookieMap)
                .userAgent(SpiderUtil.UA[new Random().nextInt(SpiderUtil.UA.length)])
                .timeout(15000).get();
            return doc.getElementById("sec_key").text();
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }

    public JSONObject bindValidator(String cookies, String csrfToken, String password) {
        final HttpRequest request = HttpUtil.createPost(this.host + VALIDATOR_BIND_PATH);
        String params = String.format("SPassword=%s&Data={\"Data\":{}}", password);
        request.header("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
        request.header("x-requested-with", "XMLHttpRequest");
        request.header("x-csrf-token", csrfToken);
        request.cookie(cookies);
        request.body(URLEncoder.createQuery().encode(params, CHARSET_UTF_8));
        String ret;
        try {
            ret = request.execute().body();
            if (StringUtils.contains(ret, "Redirecting")) {
                throw new LoginErrorException("");
            }
            return JSON.parseObject(ret);
        } catch (LoginErrorException le) {
            throw new LoginErrorException(le.getMessage());
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public JSONObject reBindValidator(String cookies, String csrfToken, String password) {
        final HttpRequest request = HttpUtil.createPost(this.host + VALIDATOR_CLEAR_BIND_PATH);
        String params = String.format("SPassword=%s&Data={\"Data\":{}}", password);
        request.header("x-requested-with", "XMLHttpRequest");
        request.header("x-csrf-token", csrfToken);
        request.cookie(cookies);
        String ret;
        try {
            ret = request.execute().body();
            if (StringUtils.contains(ret, "Redirecting")) {
                throw new LoginErrorException("");
            }
            return JSON.parseObject(ret);
        } catch (LoginErrorException le) {
            throw new LoginErrorException(le.getMessage());
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public JSONObject getHistory(String cookies, Long id) {
        JSONObject result = new JSONObject();
        final HttpRequest request = HttpUtil.createGet(this.host + DETAIL_PATH + id);
        request.cookie(cookies);
        try {
            JSONObject listJson = JSON.parseObject(request.execute().body());
            JSONArray array = listJson.getJSONArray("model");
            if (array.size() == 0) {
                return new JSONObject();
            }

            Map<Integer, List<JSONObject>> group = Maps.newHashMap();

            int countWin = 0;
            int countLose = 0;
            for (int i = 0; i < array.size(); i++) {
                JSONObject jsonObject = (JSONObject) array.get(i);
                // 月份 托管 胜 负
                String openTime = jsonObject.getString("opentime");
                Integer month = CommonUtil.getMonth(openTime);
                group.computeIfAbsent(month, k -> Lists.newArrayList());
                group.get(month).add(jsonObject);

                String aWin = jsonObject.getString("Awin");
                if (StringUtils.startsWith(aWin, "-")) {
                    countLose += 1;
                } else {
                    countWin += 1;
                }
            }

            List<Map<String, Object>> details = Lists.newArrayList();
            group.forEach((m, data) -> {
                Map<String, Object> detail = Maps.newHashMap();
                detail.put("month", m);
                detail.put("trade", data.get(0).getString("partnername"));
                detail.put("lose", data.stream().filter(d -> d.getString("Awin").startsWith("-")).count());
                detail.put("win", data.stream().filter(d -> !d.getString("Awin").startsWith("-")).count());
                details.add(detail);
            });
            result.put("win", countWin);
            result.put("lose", countLose);
            result.put("details", details);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    public TransferUResponse getTransferU(String cookies) {
        final HttpRequest request = HttpUtil.createGet(host + TRANSFER_U_LIST_PATH);
        request.cookie(cookies);
        final String ret = request.execute().body();
        try {
            return JSON.parseObject(ret, TransferUResponse.class);
        } catch (Exception e) {
            System.out.println(ret);
            return null;
        }
    }

    public JSONObject updatePassword(String cookies, String csrfToken, String password, String verifyCode) {
        final HttpRequest request = HttpUtil.createPost(host + PASSWORD_PATH)
            .form("SPassword", verifyCode)
            .form("Data", String.format("{\"Data\":[{\"getPassword1\":\"%s\",\"getPassword2\":\"%s\",\"captcha\":\"undefined\"}]}", password, password));
        request.header("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
        request.header("x-requested-with", "XMLHttpRequest");
        request.header("x-csrf-token", csrfToken);
        request.cookie(cookies);
        String ret;
        try {
            ret = request.execute().body();
            return JSON.parseObject(ret);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public JSONObject getVerifyCode(String cookies, String csrfToken) {
        final HttpRequest request = HttpUtil.createPost(host + VERIFY_PATH);
        request.header("x-requested-with", "XMLHttpRequest");
        request.header("x-csrf-token", csrfToken);
        request.cookie(cookies);
        String ret;
        try {
            ret = request.execute().body();
            if (StringUtils.contains(ret, "Redirecting")) {
                throw new LoginErrorException("");
            }
            return JSON.parseObject(ret);
        } catch (LoginErrorException le) {
            throw new LoginErrorException(le.getMessage());
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public JSONObject getCNY() {
        final HttpRequest request = HttpUtil.createGet(RATE_PATH);
        try {
            JSONObject jsonObject = JSON.parseObject(request.execute().body());
            return jsonObject.getJSONObject("result");
        } catch (Exception e) {
            e.printStackTrace();
            return new JSONObject();
        }
    }

    public Element getBalance(String cookies) {
        Map<String, String> cookieMap = CommonUtil.cookieToMap(cookies);

        Document doc;
        try {
            doc = Jsoup.connect(host + CHS_PATH).ignoreHttpErrors(true)
                .ignoreContentType(true)
                .cookies(cookieMap)
                .userAgent(SpiderUtil.UA[new Random().nextInt(SpiderUtil.UA.length)])
                .timeout(15000).get();
            return doc;
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }

    public HttpResponse cancel(String cookies, String csrfToken, String pwd, Long id) {
        final HttpRequest request = HttpUtil.createPost(host + CANCEL_PATH);
        request.cookie(cookies);
        request.header("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
        request.header("x-csrf-token", csrfToken);

        String params = String.format("SPassword=%s&{\"Data\":{\"id\":\"%s\",\"step\":\"1\"}}", pwd, id);
        request.body(URLEncoder.createQuery().encode(params, CHARSET_UTF_8));
        HttpResponse response = request.execute();

        return response;
    }

    public HttpResponse convertU(String cookies, String csrfToken, String totpCode, String password, BigDecimal amount) {
        final HttpRequest request = HttpUtil.createPost(host + CONVERT_U_PATH);
        request.cookie(cookies);
        request.header("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
        request.header("x-csrf-token", csrfToken);
        String params = String.format("SPassword=%s&Data={\"Data\":[{\"amount\":\"%s\",\"sec_pass\":\"%s\"}]}", totpCode, amount, password);
        request.body(URLEncoder.createQuery().encode(params, CHARSET_UTF_8));
        return request.execute();
    }

    public HttpResponse convertU2(String cookies, String csrfToken, String totpCode, String password, BigDecimal amount) {
        final HttpRequest request = HttpUtil.createPost(host + CONVERT_U_PATH);
        request.cookie(cookies);
        request.header("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
        request.header("x-csrf-token", csrfToken);
        String params = String.format("SPassword=%s&Data={\"Data\":[{\"amount\":\"%s\"}]}", password, amount);
        request.body(URLEncoder.createQuery().encode(params, CHARSET_UTF_8));
        return request.execute();
    }

    public HttpResponse transferU2(String cookies, String csrfToken, String totpCode, String password, String toUser, BigDecimal amount) {
        final HttpRequest request = HttpUtil.createPost(host + TRANSFER_U_PATH);
        String params = String
            .format("SPassword=%s&Data={\"Data\":{\"amount\":\"%s\",\"to_username\":\"%s\",\"remark\":\"\",\"network\":\"up\",\"t_method\":\"1\"}}", password, amount, toUser,
                password);
        request.cookie(cookies);
        request.header("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
        request.header("x-csrf-token", csrfToken);
        request.header("x-requested-with", "XMLHttpRequest");
        request.body(URLEncoder.createQuery().encode(params, CHARSET_UTF_8));

        return request.execute();
    }

    public HttpResponse transferU(String cookies, String csrfToken, String totpCode, String password, String toUser, BigDecimal amount) {
        final HttpRequest request = HttpUtil.createPost(host + TRANSFER_U_PATH);
        String params = String
            .format("SPassword=%s&Data={\"Data\":{\"amount\":\"%s\",\"to_username\":\"%s\",\"remark\":\"\",\"network\":\"up\",\"t_method\":\"1\",\"sec_pass\":\"%s\"}}", totpCode, amount, toUser,
                password);
        request.cookie(cookies);
        request.header("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
        request.header("x-csrf-token", csrfToken);
        request.header("x-requested-with", "XMLHttpRequest");
        request.body(URLEncoder.createQuery().encode(params, CHARSET_UTF_8));

        return request.execute();
    }

    public HttpResponse getFunds(String cookies) {
        final HttpRequest request = HttpUtil.createGet(host + FUNDS_PATH);
        request.cookie(cookies);
        return request.execute();
    }

    public HttpResponse getCsrfToken() {
        final HttpRequest request = HttpUtil.createGet(host + CSRF_PATH);
        return request.execute();
    }

    public HttpResponse getImage(List<HttpCookie> cookies) {
        final HttpRequest request = HttpUtil.createGet(host + CAPTCHA_CODE_PATH);
        request.cookie(cookies);
        return request.execute();
    }

    public HttpResponse login(HttpResponse imageResponse, String csrfToken, LoginRequest login) {
        final HttpRequest request = HttpUtil.createPost(host + CSRF_PATH);
        if (null != imageResponse) {
            request.cookie(imageResponse.getCookies());
        }
        request.header("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
        request.header("X-CSRF-TOKEN", csrfToken);
        request.body(login.toString());
        return request.execute();
    }

    public static List<String> matchKeyElement(String source, String key) {
        List<String> result = new ArrayList<>();
        String reg = "name=\"" + key + "\" content=\"(.+?)/>";
        Matcher m = Pattern.compile(reg).matcher(source);
        while (m.find()) {
            String r = m.group(1);
            result.add(StringUtils.replace(r, "\"", "").trim());
        }
        return result;
    }

}
